package com.hzz.gulimall.search.thread;

import java.util.concurrent.*;

public class ThreadTest {
    public static ExecutorService executor= Executors.newFixedThreadPool(10);
    public void thread(String[] args) throws ExecutionException, InterruptedException {

        System.out.println("main..start..");
        //        Thread01 thread01 = new Thread01();
//        thread01.setName("哈哈线程");
//        thread01.start();
//        System.out.println("main..stop..");
        //FutureTask类实现了RunnableFuture接口继承了Runnable 和 Future<V>接口
//        FutureTask<Integer> futureTask = new FutureTask<>(new Callable01());
//        new Thread(futureTask).start();
//        //等待线程执行完成，获取返回结果 ,因为要等待返回结果，所以main线程后执行完
//        Integer integer = futureTask.get();
//        System.out.println("main..stop.."+integer);
        /**
         *  1.继承thread类
         *  2.实现Runnable接口
         *  3.实现Callable接口+FutureTask(可以拿到返回结果，可以处理异常)
         *  4.线程池，直接提交任务  (ExecutorService)  service.execute(); 里面传入 new Runable01
         *    :创建方式
         *    1.executors  Executors.newFixedThreadPool
         *    2.
         * 区别：1.2.3没有资源控制 只有4可以控制资源
         * 线程池原生 7大参数
         *  1.核心线程数
         *  2.最大线程数
         *  3.非核心线程存活时间
         *  4.时间单位
         *  5.workQueue阻塞队列：如果任务很多，就会将目前的任务放在队列里面，只要有线程空闲
         *  就会从队列里面取出新的任务继续执行
         *  6.线程的创建工厂
         *  7.拒绝策略:如果队列满了，按照我们指定的拒绝策略拒绝执行任务
         *
         *
         *  工作顺序(重点)
         *  1.线程池创建，将准备好core数量的核心线程，准备接收新任务
         *  2.core满了，就将再进来的任务放入阻塞队列中，空闲的core就会自已去阻塞队列中去任务执行
         *  3.阻塞队列满了，就直接开新的线程执行，最大只能开到max指定的位置可以为无界、有界、同步移交三种队列类型之一
         *  4.max满了就用hander 拒绝任务
         *  5.max执行完成，有很多空闲，在指定的时间keepaliveTime以后，释放max-core这些线程
         *
         *  注释：new LinkedBlockingQueue<>(), 默认是integer的最大值，内存不够
         *
         *  面试题：一个线程池 core7,max20，queue50, 100并发进来如何分配
         *  答:7个会立即执行，50个会进入队列，队列满了，再开13个线程，总计70个，剩下的30个
         *  就使用拒绝策略执行，如果不想抛弃还要执行使用callerRunsPolicy (同步的方式)
         *  Future:最大的特点就是可以获取异步的结果
         *  优点：1.降低资源的消耗：(降低线程的创建和销毁带来的损耗)
         *       2.提高响应速度，3.提高线程的可管性
         */

        ThreadPoolExecutor executor = new ThreadPoolExecutor(5,
                200,
                10,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(100000),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy()
                );
        /*Executors.newCachedThreadPool();  core是0，所有都可以回收
        Executors.newFixedThreadPool(11);   固定大小，core=max;都不可回收
        Executors.newScheduledThreadPool(11); 定时任务的线程池
        Executors.newSingleThreadExecutor(); 单线程的线程池，后台从队列里面获取任务，挨个执行
        */
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main..start..");
//        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
//            System.out.println("当前线程:" + Thread.currentThread().getId());
//            int i = 10 / 2;
//            System.out.println("运行结果" + i);
//        }, executor);
        //有返回值的异步编排,方法完成后的感知
//        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
//            System.out.println("当前线程:" + Thread.currentThread().getId());
//            int i = 10 / 0;
//            System.out.println("运行结果" + i);
//            return i;
//        }, executor).whenComplete((res,execption)->{
//            //s虽然能得到异常信息，但是没法修改返回结果
//            System.out.println("异步任务完成了..结果是"+res+"异常是"+execption);
//        }).exceptionally(throwable -> {
//            //可以感知异常，同时返回默认值
//            return 10;
//        });
        //方法执行完成后的处理
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 / 4;
            System.out.println("运行结果" + i);
            return i;
        }, executor).handle((res,thr)->{
            if (res!=null){
                return res*2;
            }
            if(thr!=null){
                return 0;
            }
            return 0;
        });
        Integer integer = future.get();
        System.out.println("main..stop.."+integer);
        /**
         *  线程串长化
         *  1).thenrun:不能获取到上一步执行结果
         *  .thenRunAsync(() -> {
         *             System.out.println("任务2启动了");
         *         }, executor);
         *  2.thenAcceptAsync 能接受上一步结果但是无返回值
         *  3.thenApplyAsync 能接受上一步结果且返回值
         */
//        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
//            System.out.println("当前线程:" + Thread.currentThread().getId());
//            int i = 10 / 4;
//            System.out.println("运行结果" + i);
//            return i;
//        }, executor).thenApplyAsync(res -> {
//            System.out.println("任务2启动了" + res);
//            return "hello" + res;
//        }, executor);
//        //future.get()阻塞方法
//        System.out.println("main..end.."+future.get());

        //哪怕有很多默认方法，只要接口只定义了一个抽象方法，它就是一个函数式接口。
        //Lambda表达式允许你直接以内联的形式为函数式接口的抽象方法提供实现， 并把整个表达式作为函数式接口的实例
        // 使用匿名类
//        Runnable r2 = new Runnable() {
//            public void run() {
//                System.out.println("Hello World 2");
//            }
//        };
//        Runnable r1=()->{
//            System.out.println("hellor1");
//        };
//        new Thread(()->{
//            System.out.println("xx");
//        }).start();
    }
    public static class Thread01 extends Thread{
        @Override
        public void run() {
            System.out.println("当前线程:"+Thread.currentThread().getName());
            int i=10/2;
            System.out.println("运行结果"+i);
        }
    }
    public static class Callable01 implements Callable<Integer>{

        @Override
        public Integer call() throws Exception {
            System.out.println("当前线程:"+Thread.currentThread().getName());
            int i=10/2;
            System.out.println("运行结果"+i);
            return i;
        }
    }
    public static class Runable01 implements Runnable{

        @Override
        public void run() {
            System.out.println("当前线程:"+Thread.currentThread().getName());
            int i=10/2;
            System.out.println("运行结果"+i);
        }
    }
}
